
package com.badlogic.gdx.tools.flame;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.Insets;

import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;

import com.badlogic.gdx.utils.Array;

/** @author Inferno */
public class TemplatePickerPanel<T> extends EditorPanel<Array<T>> implements LoaderButton.Listener<T> {

	public interface Listener<T> {
		void onTemplateChecked (T template, boolean isChecked);
	}

	Array<T> loadedTemplates;
	Array<T> excludedTemplates;
	Class<T> type;
	JTable templatesTable;
	DefaultTableModel templatesTableModel;
	boolean isOneModelSelectedRequired = true, isMultipleSelectionAllowed = true;
	Listener listener;
	int lastSelected = -1;

	public TemplatePickerPanel (FlameMain editor, Array<T> value, Listener listener, Class<T> type) {
		this(editor, value, listener, type, null, true, true);
	}

	public TemplatePickerPanel (FlameMain editor, Array<T> value, Listener listener, Class<T> type, LoaderButton<T> loaderButton) {
		this(editor, value, listener, type, loaderButton, true, true);
	}

	public TemplatePickerPanel (FlameMain editor, Array<T> value, Listener listener, Class<T> type, LoaderButton<T> loaderButton,
		boolean isOneModelSelectedRequired, boolean isMultipleSelectionAllowed) {
		super(editor, "", "");
		this.type = type;
		this.listener = listener;
		this.isOneModelSelectedRequired = isOneModelSelectedRequired;
		this.isMultipleSelectionAllowed = isMultipleSelectionAllowed;
		loadedTemplates = new Array<T>();
		excludedTemplates = new Array<T>();
		initializeComponents(type, loaderButton);
		setValue(value);
	}

	@Override
	public void setValue (Array<T> value) {
		super.setValue(value);
		if (value == null) return;
		if (!isMultipleSelectionAllowed && value.size > 1) throw new RuntimeException(
			"Multiple selection must be enabled to ensure consistency between picked and available models.");
		for (int i = 0; i < value.size; ++i) {
			T model = value.get(i);
			int index = loadedTemplates.indexOf(model, true);
			if (index > -1) {
				EditorPanel.setValue(templatesTableModel, true, index, 1);
				lastSelected = index;
			}
		}
	}

	public void setOneModelSelectionRequired (boolean isOneModelSelectionRequired) {
		this.isOneModelSelectedRequired = isOneModelSelectionRequired;
	}

	public void setMultipleSelectionAllowed (boolean isMultipleSelectionAllowed) {
		this.isMultipleSelectionAllowed = isMultipleSelectionAllowed;
	}

	public void setExcludedTemplates (Array<T> excludedTemplates) {
		this.excludedTemplates.clear();
		this.excludedTemplates.addAll(excludedTemplates);
	}

	public void setLoadedTemplates (Array<T> templates) {
		loadedTemplates.clear();
		loadedTemplates.addAll(templates);
		loadedTemplates.removeAll(excludedTemplates, true);
		templatesTableModel.getDataVector().removeAllElements();
		int i = 0;
		for (T template : templates) {
			templatesTableModel.addRow(new Object[] {getTemplateName(template, i), false});
			i++;
		}
		lastSelected = -1;
		setValue(value);
	}

	protected String getTemplateName (T template, int index) {
		String name = editor.assetManager.getAssetFileName(template);
		return name == null ? "template " + index : name;
	}

	public void reloadTemplates () {
		setLoadedTemplates(editor.assetManager.getAll(type, new Array<T>()));
	}

	protected void initializeComponents (Class<T> type, LoaderButton<T> loaderButton) {
		int i = 0;
		if (loaderButton != null) {
			loaderButton.setListener(this);
			contentPanel.add(loaderButton, new GridBagConstraints(0, i++, 1, 1, 1, 0, GridBagConstraints.CENTER,
				GridBagConstraints.BOTH, new Insets(0, 0, 0, 6), 0, 0));
		}

		JScrollPane scroll = new JScrollPane();
		contentPanel.add(scroll, new GridBagConstraints(0, i, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
			new Insets(0, 0, 0, 6), 0, 0));
		{
			templatesTable = new JTable() {
				public Class getColumnClass (int column) {
					return column == 1 ? Boolean.class : super.getColumnClass(column);
				}

				@Override
				public Dimension getPreferredScrollableViewportSize () {
					Dimension dim = super.getPreferredScrollableViewportSize();
					dim.height = getPreferredSize().height;
					return dim;
				}
			};
			templatesTable.getTableHeader().setReorderingAllowed(false);
			templatesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
			scroll.setViewportView(templatesTable);
			templatesTableModel = new DefaultTableModel(new String[0][0], new String[] {"Template", "Selected"});
			templatesTable.setModel(templatesTableModel);
			reloadTemplates();

			templatesTableModel.addTableModelListener(new TableModelListener() {
				public void tableChanged (TableModelEvent event) {
					if (event.getColumn() != 1) return;
					int row = event.getFirstRow();
					boolean checked = (Boolean)templatesTable.getValueAt(row, 1);
					if (isOneModelSelectedRequired && (value.size == 1 && !checked)) {
						EditorPanel.setValue(templatesTableModel, true, row, 1);
						return;
					}

					templateChecked(row, checked);
				}
			});
		}
	}

	protected void templateChecked (int index, Boolean isChecked) {
		T template = loadedTemplates.get(index);
		if (isChecked) {
			if (!isMultipleSelectionAllowed) {
				if (lastSelected > -1) {
					value.removeValue(loadedTemplates.get(lastSelected), true);
					EditorPanel.setValue(templatesTableModel, false, lastSelected, 1);
				}
			}
			value.add(template);
			lastSelected = index;
		} else {
			value.removeValue(template, true);
		}
		listener.onTemplateChecked(template, isChecked);
	}

	@Override
	public void onResourceLoaded (T model) {
		reloadTemplates();
		if (lastSelected == -1 && isOneModelSelectedRequired) {
			templateChecked(loadedTemplates.size - 1, true);
		} else {
			setValue(value);
		}

		revalidate();
		repaint();
	}

}
